/********************************************************************************
 * @file    backtrack.c
 * @author  jianqiang.xue
 * @version V1.0.0
 * @date    2023-02-10
 * @brief   记录错误原因，方便追溯问题源
 ********************************************************************************/
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>

#include "RTE_Components.h"
#include CMSIS_device_header

#include "cmsis_os2.h"
#include "os_api.h"
#include "atcmd_slave.h" // 自行添加[Module\atcmd\atcmd_slave.c]

#include "kv_sys.h"
#include "bsp_uart.h"

typedef struct __PACKED {
    uint32_t event; // 0--HardFault 1--DefaultISR 2--osRtxErrorNotify
    // HardFault_Handler
    uint32_t r0;
    uint32_t r1;
    uint32_t r2;
    uint32_t r3;
    uint32_t r12;
    uint32_t lr;
    uint32_t pc;
    uint32_t psr;
    uint64_t BFAR;
    uint64_t CFSR;
    uint64_t HFSR;
    uint64_t DFSR;
    uint64_t AFSR;
    uint64_t SCB_SHCSR;

    // DefaultISR
    uint32_t VECTORNUM_ADDR;

    // osRtxErrorNotify
    uint32_t RTX_CODE;
    uint32_t RTX_OBJ_ID;
} HardFault_t;

void HardFault_Handler_C(unsigned int* hardfault_args) {
    char buff[100];
    uint8_t len = 0;
    HardFault_t info;
    info.r0 = ((unsigned long)hardfault_args[0]);
    info.r1 = ((unsigned long)hardfault_args[1]);
    info.r2 = ((unsigned long)hardfault_args[2]);
    info.r3 = ((unsigned long)hardfault_args[3]);

    info.r12 = ((unsigned long)hardfault_args[4]);
    info.lr = ((unsigned long)hardfault_args[5]);
    info.pc = ((unsigned long)hardfault_args[6]);
    info.psr = ((unsigned long)hardfault_args[7]);
    info.BFAR = (*((volatile unsigned long*)(0xE000ED38)));
    info.CFSR = (*((volatile unsigned long*)(0xE000ED28)));
    info.HFSR = (*((volatile unsigned long*)(0xE000ED2C)));
    info.DFSR = (*((volatile unsigned long*)(0xE000ED30)));
    info.AFSR = (*((volatile unsigned long*)(0xE000ED3C)));
    info.SCB_SHCSR = SCB->SHCSR;
    len = snprintf(buff, 100, "\n[Hard fault handler - all num in hex] %x\r\n", *hardfault_args);
    bsp_uart_send_nbyte(BSP_UART_0, (uint8_t *)buff, len);

    len = snprintf(buff, 100, "\nR0 = %x\r\nR1 = %x\r\nR2 = %x\r\nR3 = %x\r\nR12 = %x\r\n", info.r0, info.r1, info.r2, info.r3, info.r12);
    bsp_uart_send_nbyte(BSP_UART_0, (uint8_t *)buff, len);

    len = snprintf(buff, 100, "\nLR [R14] = %x,sub call return addr\r\nPC [R15] = %x,program counter\r\nPSR = %x\r\n", info.lr, info.pc, info.psr);
    bsp_uart_send_nbyte(BSP_UART_0, (uint8_t *)buff, len);

    len = snprintf(buff, 100, "\nBFAR = %llx\r\nCFSR = %llx\r\nHFSR = %llx\r\nDFSR = %llx\r\nAFSR = %llx\r\nSCB_SHCSR = %llx\r\n",
           info.BFAR, info.CFSR, info.HFSR, info.DFSR, info.AFSR, info.SCB_SHCSR);
    bsp_uart_send_nbyte(BSP_UART_0, (uint8_t *)buff, len);
    info.event = 0;
    kv_set_env(0xFF00, &info, sizeof(HardFault_t)); // 记录到Flash
    while (1);
}

#define VECTORNUM    (*(volatile uint32_t*)(0xE000ED04))
void DefaultISR(void) {
    HardFault_t info;
    printf("\n default_isr %d,%x \r\n",  (uint8_t)VECTORNUM, (uint32_t)VECTORNUM);
    info.event = 1;
    info.VECTORNUM_ADDR = VECTORNUM;
    kv_set_env(0xFF00, &info, sizeof(HardFault_t)); // 记录到Flash
    while(1);
}

uint32_t osRtxErrorNotify(uint32_t code, void* object_id) {
    HardFault_t info;
    (void)object_id;
//    uint8_t data[100], len = 0;
    switch (code) {
        case osRtxErrorStackOverflow:
            printf("\n Stack overflow detected for thread (thread_id=0x%x)\n", (uint32_t)object_id);
            // Stack overflow detected for thread (thread_id=object_id)
            break;
        case osRtxErrorISRQueueOverflow:
            printf("\n ISR Queue overflow detected when inserting object 0x%x\n", (uint32_t)object_id);
            // ISR Queue overflow detected when inserting object (object_id)
            break;
        case osRtxErrorTimerQueueOverflow:
            //printf("\n User Timer Callback Queue overflow detected for timer (timer_id=0x%x)\n", (uint32_t)object_id);
            // User Timer Callback Queue overflow detected for timer (timer_id=object_id)
            break;
        case osRtxErrorClibSpace:
            printf("\n Standard C/C++ library libspace not available: increase OS_THREAD_LIBSPACE_NUM 0x%x\n", (uint32_t)object_id);
            // Standard C/C++ library libspace not available: increase OS_THREAD_LIBSPACE_NUM
            break;
        case osRtxErrorClibMutex:
            printf("\n Standard C/C++ library mutex initialization failed 0x%x\n", (uint32_t)object_id);
            // Standard C/C++ library mutex initialization failed
            break;
        default:
            // Reserved
            break;
    }
    info.event = 2;
    info.RTX_CODE = code;
    info.RTX_OBJ_ID = (uint32_t)object_id;
//    kv_set_env(0xFF00, &info, sizeof(HardFault_t)); // 记录到Flash
//    for (;;) {
//    }
    return 0U;
}

#ifdef ATCMD_EN
// 在功能模块中定义一个标准函数
static int atcmd_backtrack(atcmd_pack_t *pack) {
    HardFault_t *info = NULL;
    uint8_t buff[100], len = 0;
    info = kv_get_env(0xFF00);
    if (info == NULL) {
        strcat((char*)buff, AT_ERROR);
    } else {
        if (info->event == 0) {
            len = snprintf((char *)buff, 100, "R0 = %x\r\nR1 = %x\r\nR2 = %x\r\nR3 = %x\r\nR12 = %x\r\n", info->r0, info->r1, info->r2, info->r3, info->r12);
            pack->reply(buff, len);
            len = snprintf((char *)buff, 100, "LR [R14] = %x,sub call return addr\r\n", info->lr);
            pack->reply(buff, len);
            len = snprintf((char *)buff, 100, "PC [R15] = %x,program counter\r\n", info->pc);
            pack->reply(buff, len);
            len = snprintf((char *)buff, 100, "PSR = %x\r\nBFAR = %llx\r\n", info->psr, info->BFAR);
            pack->reply(buff, len);
            len = snprintf((char *)buff, 100, "CFSR = %llx\r\nHFSR = %llx\r\nDFSR = %llx\r\n", info->CFSR, info->HFSR, info->DFSR);
            pack->reply(buff, len);
            len = snprintf((char *)buff, 100, "AFSR = %llx\r\nSCB_SHCSR = %llx\r\n", info->AFSR, info->SCB_SHCSR);
            pack->reply(buff, len);
        } else if (info->event == 1) {
            len = snprintf((char *)buff, 100, "\n default_isr %d,%x\n", (uint8_t)info->VECTORNUM_ADDR, (uint32_t)info->VECTORNUM_ADDR);
            pack->reply(buff, len);
        } else if (info->event == 2) {
            len = snprintf((char *)buff, 100, "\n RTX_ERR CODE=0x%x, OBJ_ID=0x%x\n", (uint8_t)info->RTX_CODE, (uint32_t)info->RTX_OBJ_ID);
            pack->reply(buff, len);
        }
    }
    return 0;
}

// 注册AT指令，传入标准函数
ATCMD_INIT("AT+BACKTRACK?", atcmd_backtrack);
#endif

